 
export class ShardCommunication
{
    static _OnHandleMsg:OnHandleMsg;
    private static LocalShardData:IShardMemory;
    private static allshards:shards[] = ["shard0","shard1","shard2","shard3"];
    private static shard:shards = Game.shard.name as shards;
    private static _RemoteMemory:{[key in shards]:IShardMemory};
    // 两个接口
    // listen
    // send
    // @cpu_used()
    private static LoadMemory():void
    {
        this.LocalShardData = this.GetInitShardMemory(InterShardMemory.getLocal());
        const remoteshard:{[key in string]:IShardMemory}={};
        for(const key of this.allshards)
        {
            // if(key!=Game.shard.name)
            {
                remoteshard[key] =  this.GetInitShardMemory(InterShardMemory.getRemote(key));
            }

        }
        this._RemoteMemory = remoteshard as {[key in shards]:IShardMemory};
        // console.log("LoadMemory:"+JSON.stringify(this._RemoteMemory));
    }
    // @cpu_used()
    public static SaveMemory():void
    {
        if (!Game.cpu.generatePixel) return
        const curtickdata = JSON.stringify(this.LocalShardData);

        InterShardMemory.setLocal(curtickdata);

    }
    // @cpu_used()
    public static Listen():void
    {
        if (!Game.cpu.generatePixel) return
        if(this.shard.startsWith('shard')==false)
        {
            return ;
        }

        this.LoadMemory();

        for(const item of this.allshards)
        {
            this.ListenDataSegment(item);
        }

        this.ListenCleanSegment();

        // this.SaveMemory();
    }
    // 监听我要接收的数据,然后同步到本shard
    // @cpu_used()
    private  static  ListenDataSegment(shard:shards):void
    {
        const shardmem = this.GetRemoteMemory(shard);
        if(!this.LocalShardData.ReceivedSegment)
        {
            console.log(`本shard ${this.shard} 与 ${shard} ->尚未建立通信 [${shard}]的脚本无法执行 不能初始化远程脚本`);
            return
        }
        const localreceivedSegnemt = this.LocalShardData.ReceivedSegment[shard];

        // 监听远程消息
        // 保存远程数据宝本地。重复的就丢弃,没有的就接收
        const receivedMsg = shardmem.SendSegment[this.shard as shards];
        // this.LocalShardData.ReceivedSegment[shard]  = receivedMsg;

        for(const key in receivedMsg.DataSegment)
        {
            const msg = receivedMsg.DataSegment[key];
            if(msg && !localreceivedSegnemt.DataSegment[key])
            {
                msg.ttl=100;    // 接收到消息后在100t之内处理
                localreceivedSegnemt.DataSegment[key] = msg;
            }
        }
    }

    // 监听我要发送的数据是否发送完成。
    private  static ListenCleanSegment():void
    {
        // 监听我要发送的数据是否完成,清理发送的数据

        for(const shard  in this.LocalMemory.SendSegment)
        {
            const shardflag = this.LocalMemory.SendSegment[shard as shards];

            for(let msgkey in shardflag.DataSegment)
            {
                // 同时监听消息是否超时了
                if(this.IsMessageReady(shard as shards,msgkey))
                {
                    // 发送过去了
                    delete shardflag.DataSegment[msgkey];
                    continue;
                }

                shardflag.DataSegment[msgkey].ttl--;
                if(shardflag.DataSegment[msgkey].ttl<0)
                {
                    delete shardflag.DataSegment[msgkey];
                }
            }
        }

        // 清理接收的数据
        for(const e of this.allshards)
        {

            for(const key in this.LocalShardData.ReceivedSegment[e].DataSegment)
            {
                const msg = this.LocalShardData.ReceivedSegment[e].DataSegment[key];
                if(msg)
                {
                    if( this._OnHandleMsg(msg))
                    {
                        // 如果处理成功，则删除
                        delete this.LocalShardData.ReceivedSegment[e].DataSegment[key];
                        continue;
                    }
                    // 接收消息是否需要超时判断
                    msg.ttl--;
                    if(msg.ttl<0)
                    {
                        // 超时清除消息
                        delete this.LocalShardData.ReceivedSegment[e].DataSegment[key];
                    }
                }

            }

        }
    }


    /**
     * 发送Creep的跨shard数据
     * @param shard
     * @param entitycache
     * @param creep
     */
    public static  SendCreepTask(shard:shards,entitycache:any,creep:Creep):void
    {
        const taskData:IShardMsgCreep={
            entity:entitycache,
            creep:creep.name,
            creepMem:_.cloneDeep(creep.memory)
        }
        const msg:IShardMessage<"IShardMsgCreep"> = {
            from:this.shard as shards,
            id:creep.name,
            type:"IShardMsgCreep",
            data:taskData,
            ttl:100,
        };
        this.Send(shard,msg);


    }
    // 将我要发送的数据压入数组中
    public static  Send(shard:shards,data:IShardMessage):void
    {
        // this.LoadMemory();
        if(!this.LocalMemory.SendSegment||  !this.LocalMemory.SendSegment[shard])
        {
             
            return;
        }
        // 1.
        if( this.LocalMemory.SendSegment[shard].DataSegment[data.id])
        {
             
            return ;
        }
        this.LocalMemory.SendSegment[shard].DataSegment[data.id] = data;

        Memory.Debug[`send Data:${this.shard}->${shard} _${data.id}`] = JSON.stringify(data);
        this.SaveMemory();
    }

    /**
     * 我的跨shard数据是否已经发过去了
     * @param shard
     * @param msgid
     */
    public static  IsMessageReady(shard:shards,msgid:string)
    {
        const shardmem = this.GetRemoteMemory(shard);
        if(!shardmem.ReceivedSegment)
        {
            //
            console.log(`本shard ${this.shard} 与 ${shard} ->尚未建立通信 [${shard}]的脚本无法执行`);
            return false;
        }
        // 监听远程消息
        // 我要发送过去的消息
        const receivedMsg = shardmem.ReceivedSegment[this.shard as shards].DataSegment[msgid];
        if(receivedMsg)
        {
            return true;
        }
        return false;
    }
    private static  GetRemoteMemory(shard:shards)
    {
        return this._RemoteMemory[shard];
    }


    private static   get LocalMemory()
    {
        return this.LocalShardData;
    }

    private  static GetInitShardMemory(data:string|null):IShardMemory
    {
        if(data && data.length>8)
        {
            // console.log("parse:data "+data);
            return JSON.parse(data);
        }
        const SendSegment:{[key in shards]:ISendSegment}={} as any;
        const ReceivedSegment:{[key in shards]:ISendSegment}={} as any;

        for(const item of this.allshards)
        {
            ReceivedSegment[item] = {shard:item,DataSegment:{}};
            SendSegment[item] = {shard:item,DataSegment:{}};
            // flagSegment[item] = {};
        }
        const shardmem:IShardMemory = {
                                        SendSegment:SendSegment ,
                                        ReceivedSegment:ReceivedSegment
                                    };
        return shardmem;
    }
}
